<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */

namespace app\service\report;

use app\model\report\ReportRecordListModel;
use app\service\alioss\AliossService;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\Writer\Exception;

final class ReportFileService extends ReportRecordBaseService
{
    public function __construct(ReportRecordListModel $pullModel)
    {
        $this->pullModel = $pullModel;
    }

    /**
     * 生成文件.
     * @param array $data 报表数据
     * @param array $merge 合并配置
     * @param array $contentData 报表信息
     * @return bool|mixed|string
     * @throws Exception
     * @throws \PhpOffice\PhpSpreadsheet\Calculation\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public static function getFile(array $data = [], array $merge = [], array $contentData = [])
    {
        // 生成excel文件流
        $spreadsheet = self::CreateFile($data, $merge);
        $fileName = $contentData['report_name'] . date('YmdHis');
        $exts = '.xlsx';
        // 导出Excel文件
        $savePath = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . 'downloads' . DIRECTORY_SEPARATOR;
        $realPath = $savePath . $fileName . $exts; // 设置导出的Excel文件名
        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save($realPath);
        clearstatcache(true, $realPath);
        if ($contentData['push_type'] == 2) {
            $exts = '.png';
            $realPath = self::getImage($realPath, $fileName);
        }
        // dd($realPath,file_exists($realPath));
        if ($contentData['push_mode'] == 1) {
            // 邮箱
            return $realPath;
        }

        // sha1加密 生成文件名 连接后缀
        $fileName = 'report_file/' . date('Ymd') . '/' . $fileName . $exts;
        // 获取OSS参数值
        $res = (new AliossService())->uploadFile($realPath, $fileName);

        if (file_exists($realPath)) {
            unlink($realPath);
        }
        return $res;
    }

    /**
     * 生成图片.
     * @param string $fileName 文件名
     * @throws Exception
     */
    public static function getImage(string $realPath = '', string $fileName = ''): string
    {
        $csvFile = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . 'downloads' . DIRECTORY_SEPARATOR . $fileName . '.csv';
        $spreadsheet = IOFactory::load($realPath);
        $worksheet = $spreadsheet->getActiveSheet(); // 获取当前工作表
        $writer = IOFactory::createWriter($spreadsheet, 'Csv');
        $writer->setDelimiter(',');
        $writer->setEnclosure('');
        $writer->setLineEnding("\r\n");
        $writer->save($csvFile);
        $data = [];
        if (($handle = fopen($csvFile, 'r')) !== false) {
            while (($row = fgets($handle)) !== false) {
                $data[] = explode(',', rtrim($row));
            }
            fclose($handle);
        }
        $delCount = 0;
        foreach ($data[0] as $rk => $val) {
            if (isset($val)) {
                // 是否展示数据
                $isShow = strpos(strval($val), '导出不展示'); // 数据类型
                if ($isShow) {
                    echo $val . PHP_EOL;
                    ++$delCount;
                    foreach ($data as $ck => $v) {
                        unset($data[$ck][$rk]);
                        // $data[$ck] = array_values($data[$ck]);
                    }
                }
            }
        }
        foreach ($data as $k => $val) {
            $data[$k] = array_values($val);
        }
        // 2. 计算行和列数
        $numRows = count($data);
        $numCols = count($data[0]);
        // 3. 创建一个图像
        $cellWidth = 300; // 单元格宽度
        $cellHeight = 80; // 单元格高度
        $imageWidth = $numCols * $cellWidth;
        $imageHeight = $numRows * $cellHeight;
        // echo $numCols . '/' . $numRows;exit;
        $image = imagecreate($imageWidth, $imageHeight);

        $font = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . 'font' . DIRECTORY_SEPARATOR . 'msyh.ttc'; // 字体文件路径，可根据需要更改
        // 5. 绘制表格和填充数据
        for ($row = 0; $row < $numRows; ++$row) {
            for ($col = 0; $col < $numCols; ++$col) {
                $x = $col * $cellWidth;
                $y = $row * $cellHeight;
                $cellValue = $data[$row][$col];
                $colIndex = Coordinate::stringFromColumnIndex($col + 2);
                $rowIndedx = $row + 1;
                $cell = $worksheet->getCell("{$colIndex}{$rowIndedx}");

                $cellStyle = $cell->getStyle();
                // 你可以访问各种样式属性，例如字体颜色、背景颜色、字体大小等
                $backgroundColor = $cellStyle->getFill()->getStartColor()->getRGB();
                $color = self::colorToRGB('#' . $cellStyle->getFont()->getColor()->getRGB());
                $groundColor = self::colorToRGB('#' . $backgroundColor);

                if (! isset($fontColor[$cellStyle->getFont()->getColor()->getRGB()])) {
                    $fontColor[$cellStyle->getFont()->getColor()->getRGB()] = imagecolorallocate($image, $color['r'], $color['g'], $color['b']);
                }
                if (! isset($bgColor[$backgroundColor])) {
                    $bgColor[$backgroundColor] = imagecolorallocate($image, $groundColor['r'], $groundColor['g'], $groundColor['b']);
                }
                // 文字大小
                $fontSize = intval($cellStyle->getFont()->getSize());
                imagefilledrectangle($image, $x, $y, $x + $cellWidth, $y + $cellHeight, $bgColor[$backgroundColor]);
                imagettftext($image, $fontSize, 0, $x + 10 + $fontSize, $y + 25, $fontColor[$cellStyle->getFont()->getColor()->getRGB()], $font, $cellValue);
            }
        }
        // 画表格边框
        $borderColor = imagecolorallocate($image, 0, 0, 0); // 黑色边框
        for ($row = 0; $row <= $numRows; ++$row) {
            for ($col = 0; $col <= $numCols; ++$col) {
                $x = $col * $cellWidth;
                $y = $row * $cellHeight;
                imageline($image, $x, 0, $x, $imageHeight, $borderColor);
                imageline($image, 0, $y, $imageWidth, $y, $borderColor);
            }
        }
        // 6. 保存图像
        $outputFile = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR . 'downloads' . DIRECTORY_SEPARATOR . $fileName . '.png';
        imagepng($image, $outputFile);

        // 清理资源
        imagedestroy($image);
        if (file_exists($csvFile)) {
            unlink($csvFile);
        }

        return $outputFile;
    }

    /**
     *  获取列表.
     * @param int $num 列号
     */
    public static function getColumn(int $num = 0): string
    {
        $str = '';
        if (floor($num / 26) > 0) {
            $str .= self::getColumn(floor($num / 26) - 1);
        }
        return $str . chr($num % 26 + 65);
    }

    /**
     * 获取rgb颜色格式.
     * @param string $color 十六进制格式
     */
    public static function colorToRGB(string $color = ''): array
    {
        $color = strtolower($color);

        // 如果颜色值是十六进制格式（以 # 开头）
        if ($color[0] === '#') {
            if (strlen($color) === 4) {
                $color = '#' . $color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3]; // 将 #RGB 转换为 #RRGGBB
            }
            $r = hexdec($color[1] . $color[2]);
            $g = hexdec($color[3] . $color[4]);
            $b = hexdec($color[5] . $color[6]);
        }
        // 如果颜色值是 RGB 格式（以 rgb(...) 开头）
        elseif (strpos($color, 'rgb') === 0) {
            $rgb = sscanf($color, 'rgb(%d, %d, %d)');
            $r = $rgb[0];
            $g = $rgb[1];
            $b = $rgb[2];
        }
        // 如果颜色值是颜色名称
        else {
            $colors = [
                'aliceblue' => 'f0f8ff', 'antiquewhite' => 'faebd7', 'aqua' => '00ffff',
                // 更多颜色
            ];
            if (array_key_exists($color, $colors)) {
                $color = $colors[$color];
                $r = hexdec(substr($color, 0, 2));
                $g = hexdec(substr($color, 2, 2));
                $b = hexdec(substr($color, 4, 2));
            } else {
                // 如果无法识别颜色，则返回默认颜色（这里是黑色）
                $r = $g = $b = 0;
            }
        }

        return [
            'r' => $r,
            'g' => $g,
            'b' => $b,
        ];
    }

    // 转化rbg
    public static function parseRgbToHex($rgb): string
    {
        $matches = [];
        if (preg_match('/rgb\((\d+), (\d+), (\d+)\)/', $rgb, $matches)) {
            $red = str_pad(dechex($matches[1]), 2, '0', STR_PAD_LEFT);
            $green = str_pad(dechex($matches[2]), 2, '0', STR_PAD_LEFT);
            $blue = str_pad(dechex($matches[3]), 2, '0', STR_PAD_LEFT);

            return strtoupper($red . $green . $blue);
        }
        // 返回默认颜色或错误值
        return '';
    }

    /**
     * 生成excel文件流.
     * @param array $data excel数据
     * @param array $merge excel合并单元格
     * @return Spreadsheet
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     */
    public static function CreateFile(array $data = [], array $merge = []): Spreadsheet
    {
        // 创建一个新的Excel文档
        $spreadsheet = new Spreadsheet();
        $worksheet = $spreadsheet->getActiveSheet();
        $data = array_filter($data, function ($data) {
            return count($data) > 0;
        });
        // 处理excel样式数据
        foreach ($data as $rk => $rowData) {
            foreach ($rowData as $ck => $columnData) {
                if (isset($columnData['v'])) {
                    $row = $rk + 1; // Excel行从1开始
                    $column = Coordinate::stringFromColumnIndex($ck + 1);
                    $value = $columnData['v'];
                    $style = $worksheet->getStyle("{$column}{$row}");
                    // echo $rk . '---' . $ck . '---' . $columnData['v'] . PHP_EOL;

                    // 设置单元格样式
                    if (! empty($columnData['ct']['fa'])) {
                        // $styleArray['font'] = ['color' => ['rgb' => trim($cell['v']['fc'], '#')]];
                        // $style->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
                        $style->getAlignment()->setVertical(Alignment::HORIZONTAL_CENTER);
                        $style->getNumberFormat()->setFormatCode($columnData['ct']['fa']);
                    }

                    // 设置字体大小
                    if (! empty($columnData['fs'])) {
                        $style->getFont()->setSize($columnData['fs']);
                    }
                    // 设置背景颜色
                    if (! empty($columnData['bg'])) {
                        if (strpos($columnData['bg'], 'rgb') !== false) {
                            $columnData['bg'] = self::parseRgbToHex($columnData['bg']);
                        }
                        $style->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB(trim($columnData['bg'], '#'));
                    }
                    // 设置字体颜色
                    if (! empty($columnData['fc'])) {
                        // $styleArray['font'] = ['color' => ['rgb' => trim($cell['v']['fc'], '#')]];
                        $style->getFont()->getColor()->setRGB(trim($columnData['fc'], '#'));
                    }
                    // 设置加粗
                    if (! empty($columnData['bl'])) {
                        $style->getFont()->setBold(true);
                    }
                    // 设置字体倾斜
                    if (! empty($columnData['it'])) {
                        $style->getFont()->setItalic(true);
                    }
                    // 设置字体倾斜
                    if (! empty($columnData['un'])) {
                        $style->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
                    }
                    // 检查是否是公式单元格
                    if (! empty($columnData['f'])) {
                        $columnData['f'] = str_replace('&', '', $columnData['f']);
                        // 将公式设置给目标单元格
                        $worksheet->setCellValue("{$column}{$row}", $columnData['f']);
                    } else {
                        if ($columnData['v'] > 100000000000) {
                            // 如果不是公式单元格，则直接设置值
                            $worksheet->setCellValueExplicit("{$column}{$row}", $value, DataType::TYPE_STRING);
                        } else {
                            $worksheet->setCellValue("{$column}{$row}", $value);
                        }
                    }
                }
            }
        }
        // 去除不展示的数据
        foreach ($data as $k => $item) {
            if ($k == 0) {
                foreach ($item as $kk => $value) {
                    if (isset($value['v'])) {
                        // 是否展示数据
                        $isShow = strpos($value['v'], '导出不展示'); // 数据类型
                        if ($isShow) {
                            $worksheet->getColumnDimension(self::getColumn($kk))->setWidth(0);
                        } else {
                            // 设置单元格自适应内容
                            // $style->getAlignment()->setWrapText(true); // 自动换行
                            // $worksheet->getRowDimension($row)->setRowHeight(-1); // 自适应行高
                            $worksheet->getColumnDimension(self::getColumn($kk))->setAutoSize(true); // 自适应列宽
                        }
                    }
                }
            }
        }
        if (! empty($merge)) {
            // 单元格合并
            foreach ($merge as $item) {
                $row = $item['r'] + 1; // Excel行从1开始
                $column = Coordinate::stringFromColumnIndex($item['c'] + 1);
                $mcRow = 0;
                $mcColumn = 0;
                if ($item['rs'] > 1) {
                    $mcRow = $item['rs'] + $row - 1;
                    $mcColumn += $item['c'] + 1;
                } else {
                    $mcRow = $row;
                    $mcColumn = $item['cs'] + $item['c'];
                }
                $mcColumn = Coordinate::stringFromColumnIndex($mcColumn);
                // 合并单元格
                $worksheet->mergeCells($column . $row . ':' . $mcColumn . $mcRow);
                // 设置合并后的单元格水平居中对齐
                $worksheet->getStyle($column . $row . ':' . $mcColumn . $mcRow)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
            }
        }
        return $spreadsheet;
    }
}
